#include "global.h"

#define AT24C02_ADDR 0xA0   // AT24C02 的设备地址，7位地址左移1位后加上读写位（0xA0表示写操作，0xA1表示读操作）
#define AT24C02_PAGE_SIZE 8 // AT24C02 的页大小（字节）

/**
 * @brief 向 AT24C02 写入一个字节数据。
 *
 * @param addr 内存地址（目标字节的地址）。
 * @param data 要写入的数据字节。
 * @return uint8_t 返回状态：SUCCESS 表示成功，ERROR 表示失败。
 */
uint8_t at24c02_writeByte(uint8_t addr, uint8_t data)
{
    i2c_start(); // 发送起始信号

    // 发送设备地址（写操作）
    i2c_sendByte(AT24C02_ADDR);
    if (i2c_receiveAck())
        return ERROR; // 检查是否成功

    // 发送内存地址（目标字节的地址）
    i2c_sendByte(addr);
    if (i2c_receiveAck())
        return ERROR; // 检查是否成功

    // 发送数据字节
    i2c_sendByte(data);
    if (i2c_receiveAck())
        return ERROR; // 检查是否成功

    i2c_stop(); // 发送停止信号

    // 延时等待写入操作完成，AT24C02 写操作需要一定的时间
    // delay_ms(5); // 根据需要的时间调整延时
    return SUCCESS; // 成功
}

/**
 * @brief 从 AT24C02 读取一个字节数据。
 *
 * @param addr 内存地址（目标字节的地址）。
 * @param data 指向存储读取数据的指针。
 * @return uint8_t 返回状态：SUCCESS 表示成功，ERROR 表示失败。
 */
uint8_t at24c02_readByte(uint8_t addr, uint8_t *data)
{
    i2c_start(); // 发送起始信号

    // 发送设备地址（写操作）
    i2c_sendByte(AT24C02_ADDR);
    if (i2c_receiveAck())
        return ERROR; // 检查是否成功

    // 发送内存地址
    i2c_sendByte(addr);
    if (i2c_receiveAck())
        return ERROR; // 检查是否成功

    i2c_start(); // 重新发起起始信号，用于开始读操作

    // 发送设备地址（读操作）
    i2c_sendByte(AT24C02_ADDR | 0x01); // 0xA1是读操作地址
    if (i2c_receiveAck())
        return ERROR; // 检查是否成功

    // 读取数据字节并通过指针传递
    *data = i2c_receiveByte(); // 将读取的数据存入传入的指针地址

    // 发送 NACK（表示没有更多数据）
    i2c_sendAck(0);

    i2c_stop();     // 发送停止信号
    return SUCCESS; // 成功
}

/**
 * @brief 向 AT24C02 写入多字节数据（分页写入）。
 *
 * @param addr 起始内存地址。
 * @param data 指向要写入数据的指针。
 * @param length 要写入的数据长度。
 * @return uint8_t 返回状态：SUCCESS 表示成功，ERROR 表示失败。
 */
uint8_t at24c02_writePage(uint8_t addr, uint8_t *data, uint8_t length)
{
    uint8_t bytesToWrite;
    uint8_t offset;

    while (length > 0)
    {
        // 计算当前页剩余空间
        offset = addr % AT24C02_PAGE_SIZE;
        bytesToWrite = AT24C02_PAGE_SIZE - offset;

        // 如果剩余数据小于等于当前页剩余空间，则直接写入
        if (bytesToWrite > length)
        {
            bytesToWrite = length;
        }

        i2c_start(); // 发送起始信号

        // 发送设备地址（写操作）
        i2c_sendByte(AT24C02_ADDR);
        if (i2c_receiveAck())
            return ERROR; // 检查是否成功

        // 发送内存地址（目标字节的地址）
        i2c_sendByte(addr);
        if (i2c_receiveAck())
            return ERROR; // 检查是否成功

        // 发送数据字节
        for (uint8_t i = 0; i < bytesToWrite; i++)
        {
            i2c_sendByte(data[i]);
            if (i2c_receiveAck())
                return ERROR; // 检查是否成功
        }

        i2c_stop(); // 发送停止信号

        // 延时等待写入操作完成，AT24C02 写操作需要一定的时间
        // delay_ms(5); // 根据需要的时间调整延时

        // 更新地址和数据指针
        addr += bytesToWrite;
        data += bytesToWrite;
        length -= bytesToWrite;
    }
    return SUCCESS; // 成功
}

/**
 * @brief 从 AT24C02 读取多字节数据。
 *
 * @param addr 起始内存地址。
 * @param data 指向存储读取数据的指针。
 * @param length 要读取的数据长度。
 * @return uint8_t 返回状态：SUCCESS 表示成功，ERROR 表示失败。
 */
uint8_t at24c02_readPage(uint8_t addr, uint8_t *data, uint8_t length)
{
    i2c_start(); // 发送起始信号

    // 发送设备地址（写操作）
    i2c_sendByte(AT24C02_ADDR);
    if (i2c_receiveAck())
        return ERROR; // 检查是否成功

    // 发送内存地址
    i2c_sendByte(addr);
    if (i2c_receiveAck())
        return ERROR; // 检查是否成功

    i2c_start(); // 重新发起起始信号，用于开始读操作

    // 发送设备地址（读操作）
    i2c_sendByte(AT24C02_ADDR | 0x01); // 0xA1是读操作地址
    if (i2c_receiveAck())
        return ERROR; // 检查是否成功

    // 读取数据字节并通过指针传递
    for (uint8_t i = 0; i < length; i++)
    {
        data[i] = i2c_receiveByte(); // 将读取的数据存入传入的指针地址

        // 发送 ACK 或 NACK
        if (i < length - 1)
        {
            i2c_sendAck(1); // 发送 ACK 表示还有更多数据
        }
        else
        {
            i2c_sendAck(0); // 发送 NACK 表示没有更多数据
        }
    }

    i2c_stop();     // 发送停止信号
    return SUCCESS; // 成功
}
